#ifndef __MARS_CORE_SHARED_PTR_H__
#define __MARS_CORE_SHARED_PTR_H__

#include "MarsType.h"
#include "MarsMacro.h"

namespace Core
{

class RefCountObject
{
public:
									RefCountObject();
									~RefCountObject();

	void							AddRef() const;
	uint32							Release() const;

	uint32							GetRefCount() const;

private:
	mutable uint32					m_iRefCount;
};

inline RefCountObject::RefCountObject()
	: m_iRefCount( 0 )
{

}

inline RefCountObject::~RefCountObject()
{
	MARS_ASSERT( m_iRefCount == 0 );
}

inline void RefCountObject::AddRef() const
{
	++m_iRefCount;
}

inline uint32 RefCountObject::Release() const
{
	uint32 iRefCount = --m_iRefCount;
	if ( m_iRefCount == 0 )
	{
		delete this;
	}

	return iRefCount;
}

inline uint32 RefCountObject::GetRefCount() const
{
	return m_iRefCount;
}

template< typename T >
class SharedPtr
{
private:
	typedef T reference_type;

public:
									SharedPtr();
									SharedPtr( reference_type* ref );
									SharedPtr( const SharedPtr& ptr );

									~SharedPtr();

	SharedPtr&						operator = ( reference_type* ref );
	SharedPtr&						operator = ( const SharedPtr& ptr );

	reference_type*					GetPointer();
	const reference_type*			GetPointer() const;

	reference_type*					operator -> () const;

	uint32							GetRefCount() const;

private:
	reference_type*					m_pReference;
};

template< typename T >
SharedPtr< T >::SharedPtr()
	: m_pReference( NULL )
{

}

template< typename T >
SharedPtr< T >::SharedPtr( reference_type* ref )
{
	m_pReference = ref;
	if ( ref )
		m_pReference->AddRef();
}

template< typename T >
SharedPtr< T >::SharedPtr( const SharedPtr& ptr )
{
	m_pReference = ptr.m_pReference;

	if ( m_pReference )
		m_pReference->AddRef();
}

template< typename T >
SharedPtr< T >::~SharedPtr()
{
	if ( m_pReference )
		m_pReference->Release();

	m_pReference = NULL;
}

template< typename T >
SharedPtr< T >&	SharedPtr< T >::operator = ( reference_type* ref )
{
	reference_type* oldRef = m_pReference;
	m_pReference = ref;
	if ( ref )
	{
		m_pReference->AddRef();
	}

	if ( oldRef )
	{
		oldRef->Release();
	}

	return *this;
}

template< typename T >
SharedPtr< T >&	SharedPtr< T >::operator = ( const SharedPtr& ptr )
{
	return *this = ptr->m_pReference;
}

template< typename T >
T*	SharedPtr< T >::GetPointer()
{
	return m_pReference;
}

template< typename T >
const T* SharedPtr< T >::GetPointer() const
{
	return m_pReference;
}

template< typename T >
T*	SharedPtr< T >::operator -> () const
{
	return m_pReference;
}

template< typename T >
uint32 SharedPtr< T >::GetRefCount() const
{
	return m_pReference->GetCount();
}

} // end of namespace Core

#endif // end of #ifndef __MARS_CORE_SHARED_PTR_H__